<?php

class Nuo_Paging_Select
{
	const ROW_COUNT_COLUMN = 'total_count';

	protected $_data = NULL;

	function __construct($data)
	{
		$this -> _data = $data;
	}

	/**
	 * Returns an array of items for a page.
	 *
	 * @param  integer $offset Page offset
	 * @param  integer $itemCountPerPage Number of items per page
	 * @return array
	 */
	public function getItems($offset, $limit)
	{
		$this -> _data -> limit($limit, $offset);

		return $this -> _data -> query() -> fetchAll();
	}

	/**
	 * Get the COUNT select object for the provided query
	 *
	 * Have a look at queries that have both GROUP BY and DISTINCT specified.
	 * In that use-case I'm expecting problems when either GROUP BY or DISTINCT
	 * has one column.
	 *
	 * @return int
	 */
	public function getTotalCount()
	{

		$rowCount = clone $this -> _data;

		$rowCount -> __toString();
		// Workaround for ZF-3719 and related

		$db = $rowCount -> getAdapter();

		$countColumn = $db -> quoteIdentifier(self::ROW_COUNT_COLUMN);
		$countPart = 'COUNT(1) AS ';
		$groupPart = null;
		$unionParts = $rowCount -> getPart(Database_Select::UNION);

		/**
		 * If we're dealing with a UNION query, execute the UNION as a subquery
		 * to the COUNT query.
		 */
		if (!empty($unionParts))
		{
			$expression = new Database_Expr($countPart . $countColumn);

			$rowCount = $db -> select() -> bind($rowCount -> getBind()) -> from($rowCount, $expression);
		}
		else
		{
			$columnParts = $rowCount -> getPart(Database_Select::COLUMNS);
			$groupParts = $rowCount -> getPart(Database_Select::GROUP);
			$havingParts = $rowCount -> getPart(Database_Select::HAVING);
			$isDistinct = $rowCount -> getPart(Database_Select::DISTINCT);

			/**
			 * If there is more than one column AND it's a DISTINCT query, more
			 * than one group, or if the query has a HAVING clause, then take
			 * the original query and use it as a subquery os the COUNT query.
			 */
			if (($isDistinct && ((count($columnParts) == 1 && $columnParts[0][1] == Database_Select::SQL_WILDCARD) || count($columnParts) > 1)) || count($groupParts) > 1 || !empty($havingParts))
			{
				$rowCount -> reset(Database_Select::ORDER);
				$rowCount = $db -> select() -> bind($rowCount -> getBind()) -> from($rowCount);
			}
			else
			if ($isDistinct)
			{
				$part = $columnParts[0];

				if ($part[1] !== Database_Select::SQL_WILDCARD && !($part[1] instanceof Database_Expr))
				{
					$column = $db -> quoteIdentifier($part[1], true);

					if (!empty($part[0]))
					{
						$column = $db -> quoteIdentifier($part[0], true) . '.' . $column;
					}

					$groupPart = $column;
				}
			}
			else
			if (!empty($groupParts))
			{
				$groupPart = $db -> quoteIdentifier($groupParts[0], true);
			}

			/**
			 * If the original query had a GROUP BY or a DISTINCT part and only
			 * one column was specified, create a COUNT(DISTINCT ) query instead
			 * of a regular COUNT query.
			 */
			if (!empty($groupPart))
			{
				$countPart = 'COUNT(DISTINCT ' . $groupPart . ') AS ';
			}

			/**
			 * Create the COUNT part of the query
			 */
			$expression = new Database_Expr($countPart . $countColumn);

			$rowCount -> reset(Database_Select::COLUMNS) -> reset(Database_Select::ORDER) -> reset(Database_Select::LIMIT_OFFSET) -> reset(Database_Select::GROUP) -> columns($expression) -> reset(Database_Select::DISTINCT) -> reset(Database_Select::HAVING);
		}

		$result = $rowCount -> query(Database::FETCH_ASSOC) -> fetch();

		$this -> _rowCount = count($result) > 0 ? $result[self::ROW_COUNT_COLUMN] : 0;
		
		return $this->_rowCount;

	}

}
